# -*- coding:utf-8 -*-
from django.db import models
from django.utils.translation import ugettext_lazy
from djwheel.utils import slugify
from utils import text2tagslist, tagslist2text

_used_tablenames = set()
_tag_slug_maxlen = 120

def create_tagmodels(tag_table_name='tags', use_slug=False):
    """Return pair of Tag, AbstractTagableModel"""
    assert not tag_table_name in _used_tablenames, "`%s` already used for tags table" % tag_table_name
    _used_tablenames.add(tag_table_name)

    class Tag(models.Model):
        name = models.CharField(ugettext_lazy('name'), max_length=255, unique=True, editable=False)
        count = models.IntegerField(ugettext_lazy('count'), default=0, editable=False)
        if use_slug:
            slug = models.SlugField(ugettext_lazy('title for url'), db_index=True,
                null=True, unique=True,
                max_length=_tag_slug_maxlen)

        class Meta:
            verbose_name = ugettext_lazy('tag')
            verbose_name_plural = ugettext_lazy('tags')
            ordering = ('name',)
            db_table = tag_table_name

        def __unicode__(self):
            return u'%s (%s)' % (self.name, self.count)

        if use_slug:
            def slug_exists(self, slug):
                #return self.__class__.objects.filter(slug=slug, name__ne=self.name).count() != 0
                return len([t for t in self.__class__.objects.filter(slug=slug) if t.id != self.id]) != 0

            def save(self, *args, **kwargs):
                if not self.slug:
                    self.slug = slugify(self.name, _tag_slug_maxlen)
                assert self.slug != ''
                i = 0
                orig_slug = self.slug
                print 'slug_exists(self.slug) `%s` %s ' % (self.slug, self.slug_exists(self.slug))
                while self.slug_exists(self.slug):
                    i += 1
                    self.slug = ('%s-%d' % (orig_slug, i))[-_tag_slug_maxlen:]
                return super(Tag, self).save(*args, **kwargs)

    class AbstractTagableModel(models.Model):
        """
        Add editable "tags_text" field
        """
        TAG_CLASS = Tag

        tags = models.ManyToManyField(Tag, editable=False)
        tags_text = models.TextField(ugettext_lazy('tags'), blank=True,
            help_text=ugettext_lazy('Comma separated, lowercase'))

        def delete(self):
            self.tags_text = ''
            self._update_tags()
            super(AbstractTagableModel, self).delete()

        def save(self, *args, **kwargs):
            if not self.pk:
                super(AbstractTagableModel, self).save(*args, **kwargs)
            self._update_tags()
            return super(AbstractTagableModel, self).save(*args, **kwargs) # double saving

        def _update_tags(self):
            old_tagnames = set(tag.name for tag in self.tags.all())
            new_tagnames = set(text2tagslist(self.tags_text))
            self.tags_text = tagslist2text(new_tagnames)

            to_delete_names = old_tagnames - new_tagnames
            to_create_names = new_tagnames - old_tagnames

            for name in to_delete_names:
                tag = Tag.objects.get(name=name)
                tag.count = tag.count - 1
                self.tags.remove(tag)
                if tag.count == 0:
                    tag.delete()
                else:
                    tag.save()

            for name in to_create_names:
                tag, created = Tag.objects.get_or_create(name=name)
                tag.count = tag.count + 1
                tag.save()
                self.tags.add(tag)
            #print 'result', self.tags.all()

        def get_tags(self):
            """
            Return related Tag objects
            """
            return self.tags.all()

        class Meta:
            abstract = True

    return Tag, AbstractTagableModel
